﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SpellCaster3.Core;
using Ultima;
using SpellCaster3.Core.Drawing;

namespace SpellCaster3.Forms
{
    public partial class IconForm : Form
    {
        #region Windows API

        private const int WS_EX_TOOLWINDOW = 0x80;

        #endregion

        #region Private fields
        private UltimaIconBitmap _UltimaIcon = new UltimaIconBitmap();
        private Point _MouseClickLocationDelta;
        private Point _LastLocation;
        private bool _Moving;
        private bool _MovedOnceFromEnter;
        private Cursor _LastCursor;
        #endregion

        #region Properties
        public int GumpIndex { get { return _UltimaIcon.GumpIndex; } set { _UltimaIcon.GumpIndex = value; } }
        public int HueIndex { get { return _UltimaIcon.HueIndex; } set { _UltimaIcon.HueIndex = value; } }
        public string Alias { get { return _UltimaIcon.Alias; } set { _UltimaIcon.Alias = value; } }
        public string KeyName { get { return _UltimaIcon.KeyName; } set { _UltimaIcon.KeyName = value; } }
        public string Description { get; set; }
        public ButtonMacro ButtonMacro { get; private set; }
        public bool Moving { get { return _Moving; } }
        #endregion

        //static IconForm()
        //{
        //    _Descriptor.ShowAlways = true;
        //    _Descriptor.ReshowDelay = 0;
        //    _Descriptor.InitialDelay = 0;
        //}

        //internal static ToolTip _Descriptor = new ToolTip();
        internal static ToolTipForm _Descriptor = new ToolTipForm();
        private const int DescriptorOffset = 16;

        public event EventHandler MoveBegin;

        public event EventHandler<MoveEventArgs> MoveEnd;

        protected void OnMoveBegin(object sender, EventArgs e)
        {
            if (MoveBegin != null) MoveBegin(sender, e);
        }

        protected void OnMoveEnd(object sender, MoveEventArgs e)
        {
            if (MoveEnd != null) MoveEnd(sender, e);
        }

        public IconForm(ButtonMacro buttonMacro)
        {
            InitializeComponent();
            _UltimaIcon.Enabled = Enabled;
            _UltimaIcon.Refresh();
            BackgroundImage = _UltimaIcon.Image;
            ButtonMacro = buttonMacro;
        }

        public IconForm() : this(new ButtonMacro()) { }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                // turn on WS_EX_TOOLWINDOW style bit
                cp.ExStyle |= WS_EX_TOOLWINDOW;
                return cp;
            }
        }

        private void IconForm_MouseMove(object sender, MouseEventArgs e)
        {
            if (_Moving)
                Location = new Point(Cursor.Position.X - _MouseClickLocationDelta.X, Cursor.Position.Y - _MouseClickLocationDelta.Y);
            _Descriptor.Location = new Point(Cursor.Position.X + ToolTipForm.PositionOffset, Cursor.Position.Y + ToolTipForm.PositionOffset);
            if (!string.IsNullOrWhiteSpace(Description) && !_Moving) _Descriptor.StartShow(Description, this);
        }

        private void IconForm_MouseDown(object sender, MouseEventArgs e)
        {
            switch (Properties.Settings.Default.UseCommandMethod)
            {
                case UseCommandMethods.LeftMouseDoubleClick:
                case UseCommandMethods.LeftMouseClick:
                    if (e.Button == MouseButtons.Right)
                    {
                        BeginMove(e.Location);
                    }
                    break;
                case UseCommandMethods.RightMouseDoubleClick:
                case UseCommandMethods.RightMouseClick:
                    if (e.Button == MouseButtons.Left)
                    {
                        BeginMove(e.Location);
                    }
                    break;
            }
        }

        private void IconForm_MouseUp(object sender, MouseEventArgs e)
        {
            if (_Moving)
                EndMove();
        }

        private void BeginMove(Point mouseLocation)
        {
            _Descriptor.Hide();
            _Moving = true;
            _MovedOnceFromEnter = true;
            _LastCursor = this.Cursor;
            this.Cursor = Cursors.SizeAll;
            _MouseClickLocationDelta.X = mouseLocation.X;
            _MouseClickLocationDelta.Y = mouseLocation.Y;
            _LastLocation = Location;
            OnMoveBegin(this, EventArgs.Empty);
        }

        private void EndMove()
        {
            _Moving = false;
            this.Cursor = _LastCursor;
            MoveEventArgs moveEventArgs = new MoveEventArgs(_LastLocation != Location ? (Point?)_LastLocation : null);
            OnMoveEnd(this, moveEventArgs);
            if (moveEventArgs.Cancel)
                Location = _LastLocation;

            if (!string.IsNullOrWhiteSpace(Description))
                _Descriptor.StartShow(Description, this);
            //Expand.ExEnvironment.Windows.ForegroundWindow = Handle;
        }

        private void DoMacro()
        {
            ButtonMacro.Execute();
        }

        private void IconForm_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            switch (Properties.Settings.Default.UseCommandMethod)
            {
                case UseCommandMethods.LeftMouseDoubleClick:
                    if (e.Button == MouseButtons.Left)
                        DoMacro();
                    break;
                case UseCommandMethods.RightMouseDoubleClick:
                    if (e.Button == MouseButtons.Right)
                        DoMacro();
                    break;
            }
        }

        private void IconForm_MouseClick(object sender, MouseEventArgs e)
        {
            switch (Properties.Settings.Default.UseCommandMethod)
            {
                case UseCommandMethods.LeftMouseClick:
                    if (e.Button == MouseButtons.Left)
                        DoMacro();
                    break;
                case UseCommandMethods.RightMouseClick:
                    if (e.Button == MouseButtons.Right)
                        DoMacro();
                    break;
            }
        }

        private void IconForm_EnabledChanged(object sender, EventArgs e)
        {
            _UltimaIcon.Enabled = Enabled;
        }

        public static IconForm FromButtonMacro(ButtonMacro macro)
        {
            IconForm frm = new IconForm(macro);
            frm.SyncWithButtonMacro(macro);
            return frm;
        }

        public void SyncWithButtonMacro(ButtonMacro macro)
        {
            GumpIndex = macro.GumpIndex;
            HueIndex = macro.HueIndex;
            Alias = macro.Alias;
            KeyName = macro.KeyName;
            Location = macro.Position;
            Description = macro.Description;
            _UltimaIcon.Refresh();
            BackgroundImage = _UltimaIcon;
        }

        private void IconForm_MouseEnter(object sender, EventArgs e)
        {
            _MovedOnceFromEnter = false;
            if (!string.IsNullOrWhiteSpace(Description) && !_Moving)
                _Descriptor.StartShow(Description, this);
        }

        private void IconForm_MouseLeave(object sender, EventArgs e)
        {
            _Descriptor.StartHide();
        }

        private void MoveWindowAndCursor(Keys key)
        {
            Point cursorClientPosition = PointToClient(Cursor.Position);
            int xClient, yClient;
            xClient = cursorClientPosition.X;
            yClient = cursorClientPosition.Y;
            int span = 1;

            switch (key)
            {
                case Keys.Left:
                    if (xClient >= (Size.Width / 2))
                    {
                        Cursor.Position = new Point(Cursor.Position.X - span, Cursor.Position.Y);
                        Location = new Point(Location.X - span, Location.Y);
                    }
                    else
                    {
                        Location = new Point(Location.X - span, Location.Y);
                        Cursor.Position = new Point(Cursor.Position.X - span, Cursor.Position.Y);
                    }
                    break;
                case Keys.Right:
                    if (xClient < (Size.Width / 2))
                    {
                        Cursor.Position = new Point(Cursor.Position.X + span, Cursor.Position.Y);
                        Location = new Point(Location.X + span, Location.Y);
                    }
                    else
                    {
                        Location = new Point(Location.X + span, Location.Y);
                        Cursor.Position = new Point(Cursor.Position.X + span, Cursor.Position.Y);
                    }
                    break;
                case Keys.Up:
                    if (yClient >= (Size.Height / 2))
                    {
                        Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - span);
                        Location = new Point(Location.X, Location.Y - span);
                    }
                    else
                    {
                        Location = new Point(Location.X, Location.Y - span);
                        Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - span);
                    }
                    break;
                case Keys.Down:
                    if (yClient < (Size.Height / 2))
                    {
                        Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + span);
                        Location = new Point(Location.X, Location.Y + span);
                    }
                    else
                    {
                        Location = new Point(Location.X, Location.Y + span);
                        Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + span);
                    }
                    break;
                default:
                    throw new InvalidOperationException();
            }
        }

        private void IconForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (_MovedOnceFromEnter)
                switch (e.KeyCode)
                {
                    case Keys.Left:
                    case Keys.Right:
                    case Keys.Up:
                    case Keys.Down:
                        MoveWindowAndCursor(e.KeyCode);
                        break;
                }
        }
    }
}
